package com.nightpiter.controller.newnet;

import static com.nightpiter.controller.log.Logger.log;
import static com.nightpiter.controller.log.Logger.logException;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Stack;

import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.os.Handler;

import com.nightpiter.controller.log.Logger;
import com.nightpiter.controller.newnet.Resource.Type;

/**
 * @author Eldar Abusalimov
 * 
 */
public class NetLister {

	public static final String ROOT = "list";

	public static final String VERSION = "version";

	public static final String MAPS = "maps";

	public static final String DRAWERS = "drawers";

	public static final String MAP = "map";

	public static final String DRAWER = "drawer";

	public static final String NAME = "name";

	public static final String DESCRIPTION = "description";

	public static final String URL = "url";

	private static ArrayList<Resource> resources;

	public static void update(final Listener listener, final Type type) {
		final Handler handler = new Handler();
		(new Thread() {
			public void run() {
				try {
					handler.post(new Runnable() {
						public void run() {
							if (listener != null) {
								listener.onObtainingStart();
							}
						}
					});
					URL url = new URL(
							"http://androidmetro.googlepages.com/list.xml");
					InputStream inputStream = url.openConnection()
							.getInputStream();
					readStream(inputStream,type);
					handler.post(new Runnable() {
						public void run() {
							if (listener != null) {
								listener.onResorcesObtained(resources);
							}
						}
					});
				} catch (Exception e) {
					logException(e);
					handler.post(new Runnable() {
						public void run() {
							if (listener != null) {
								listener.onObtainingFailed();
							}
						}
					});

				}
			}
		}).start();

	}

	/**
	 * 
	 * @param inputStream
	 * @param packBuilder
	 *            target manifest to read in
	 * @throws IOException
	 */
	private static void readStream(InputStream inputStream, Type type) throws IOException {
		try {
			SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
			XMLReader xr = parser.getXMLReader();
			EventsHandler handler = new EventsHandler(type);

			xr.setContentHandler(handler);
			xr.setErrorHandler(handler);

			InputSource inputSource = new InputSource(inputStream);

			xr.parse(inputSource);

		} catch (FactoryConfigurationError fce) {
			logException(fce);
			log("Parsing failed");
		} catch (ParserConfigurationException pce) {
			logException(pce);
			log("Parsing failed");
		} catch (SAXParseException spe) {
			logException(spe);
			log("Parsing failed");
		} catch (SAXException saxe) {
			logException(saxe);
			log("Parsing failed");
		}

	}

	/**
	 * This class handles events occurring in the SAX processing action
	 * 
	 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
	 */
	public static class EventsHandler extends DefaultHandler {

		private String version = null;

		private Stack<String> stack;

		private Resource currentResource;

		private Type type;

		public EventsHandler(Type type) {
			super();
			this.type = type;
			this.stack = new Stack<String>();
		}

		public void startDocument() {
			resources = new ArrayList<Resource>();
		}

		public void endDocument() {
		}

		public void startElement(String uri, String name, String qName,
				Attributes attrs) {

			stack.push(name);
			String path = getPath();

			if (path.equals(ROOT)) {
				this.version = attrs.getValue(VERSION);
				Logger.log("xml file version retrieved: " + this.version);

			} else if (path.equals(ROOT + MAPS + MAP)) {
				currentResource = new Resource(Type.MAP);
				if (type == Type.MAP){
					resources.add(currentResource);
				}

			} else if (path.equals(ROOT + DRAWERS + DRAWER)) {
				currentResource = new Resource(Type.DRAWER);
				if (type == Type.DRAWER){
					resources.add(currentResource);
				}

			}

		}

		public void endElement(String uri, String name, String qName) {

			stack.pop();

		}

		public void characters(char ch[], int start, int length) {
			String path = getPath();
			
			if (path.equals(ROOT + MAPS + MAP + NAME)) {
				currentResource.setName(new String(ch, start, length).trim());

			} else if (path.equals(ROOT + MAPS + MAP + URL)) {
				currentResource.setUrl(new String(ch, start, length).trim());
				
			} else if (path.equals(ROOT + MAPS + MAP + DESCRIPTION)) {
				currentResource.setDescription(new String(ch, start, length)
				.trim());
				
			} else if (path.equals(ROOT + DRAWERS + DRAWER + NAME)) {
				currentResource.setName(new String(ch, start, length).trim());

			} else if (path.equals(ROOT + DRAWERS + DRAWER + URL)) {
				currentResource.setUrl(new String(ch, start, length).trim());

			} else if (path.equals(ROOT + DRAWERS + DRAWER + DESCRIPTION)) {
				currentResource.setDescription(new String(ch, start, length)
						.trim());

			}
		}

		private String getPath() {
			String path = "";
			for (int i = 0; i < stack.size(); i++) {
				path += stack.get(i);
			}
			return path;
		}
	}

	/**
	 * 
	 * @author Eldar Abusalimov
	 * 
	 */
	public static interface Listener {

		public void onObtainingStart();

		public void onResorcesObtained(ArrayList<Resource> resources);

		public void onObtainingFailed();

	}

}
